﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace DTBuilderLib.VisualHierarchyClasses
{
    /// <summary>
    /// We hold onto a list of images, and we put them inside our own bounding image. For example,
    /// we might be a large black rect, and on the left side is a bunch of images, and on the right
    /// side some text or something else random.
    /// </summary>
    [Serializable]
    public class VisualHolder : Visual
    {
        public VisualHolder()
        {
        }

        /// <summary>
        /// The images that are "inside".
        /// </summary>
        private List<Visual> _heldImages = new List<Visual>();

        public void AddImage(Visual image)
        {
            _heldImages.Add(image);
        }

        private class BoundingBox
        {
            public double XPosition { get; set; }
            public double YPosition { get; set; }
            public double Width { get; set; }
            public double Height { get; set; }
        }

        private BoundingBox CalcBoundingBox()
        {
            double min_x = 0, max_x = 0;
            double min_y = 0, max_y = 0;
            bool x_set = false;
            bool y_set = false;
            foreach (var v in _heldImages)
            {
                double x1 = v.XPosition;
                double y1 = v.YPosition;
                double x2 = x1 + v.Width;
                double y2 = y1 + v.Height;

                if (x1 < min_x || !x_set)
                {
                    min_x = x1;
                }
                if (y1 < min_y || !y_set)
                {
                    min_y = y1;
                }

                if (x2 > max_x || !x_set)
                {
                    max_x = x2;
                }
                if (y2 > max_y || !y_set)
                {
                    max_y = y2;
                }

                y_set = true;
                x_set = true;
            }

            return new BoundingBox()
            {
                Height = (max_y - min_y),
                Width = (max_x - min_x),
                XPosition = min_x,
                YPosition = min_y
            };
        }

        public override double Width
        {
            get { return CalcBoundingBox().Width; }
        }

        public override double Height
        {
            get { return CalcBoundingBox().Height; }
        }

        /// <summary>
        /// Get or set the X position
        /// </summary>
        public override double XPosition
        {
            get
            {
                return CalcBoundingBox().XPosition;
            }
            set
            {
                BoundingBox startBox = CalcBoundingBox();
                double deltax = value - startBox.XPosition;
                foreach (var v in _heldImages)
                {
                    v.XPosition = v.XPosition + deltax;
                }
            }
        }

        public override double YPosition
        {
            get
            {
                return CalcBoundingBox().YPosition;
            }
            set
            {
                BoundingBox startBox = CalcBoundingBox();
                double deltay = value - startBox.YPosition;
                foreach (var v in _heldImages)
                {
                    v.YPosition = v.YPosition + deltay;
                }
            }
        }

        /// <summary>
        /// Scale the location of everything. This is tricky - you don't want the start position to
        /// scale, but you do want everything to correctly scale internally.
        /// </summary>
        /// <param name="factor"></param>
        public override void Scale(double factor)
        {
            BoundingBox startBox = CalcBoundingBox();
            foreach (var v in _heldImages)
            {
                v.Scale(factor);
                double x = v.XPosition;
                double y = v.YPosition;

                double xoff = (x - startBox.XPosition) * factor;
                double yoff = (y - startBox.YPosition) * factor;

                v.XPosition = startBox.XPosition + xoff;
                v.YPosition = startBox.YPosition + yoff;
            }
        }

        /// <summary>
        /// Retursn the list of scene graph nodes.
        /// NOTE: you can't do _heldImages.AsParallel because if all
        /// the guys under us are bitmaps and we are on a 8 core machine,
        /// well... that is more memory than a 32 bit process can deal with!
        /// </summary>
        internal override List<SceneGraphSceneNode> SGNodeList
        {
            get {
                var images = from v in _heldImages
                             select v.SGNodeList;
                
                List<SceneGraphSceneNode> result = new List<SceneGraphSceneNode>();
                foreach (var v in images.ToArray())
                {
                    result.AddRange(v);
                }
                return result;
            }
        }

        /// <summary>
        /// Inc everyone's z index by some number.
        /// </summary>
        /// <param name="delta"></param>
        public override void IncZIndex(int delta)
        {
            foreach (var v in _heldImages)
            {
                v.IncZIndex(delta);
            }
        }

        /// <summary>
        /// We don't have a Zindex - so fail!
        /// </summary>
        public override int ZIndex
        {
            get
            {
                int z = -1;
                foreach (var v in _heldImages)
                {
                    int znew = v.ZIndex;
                    if (znew < z || z < 0)
                    {
                        z = znew;
                    }
                }
                if (z < 1)
                {
                    z = 1;
                }
                return z;
            }
        }

        /// <summary>
        /// Return all the sub-visuals that we 
        /// </summary>
        /// <returns></returns>
        public override System.Collections.Generic.IEnumerator<Visual> GetEnumerator()
        {
            foreach (var v in _heldImages)
            {
                yield return v;
            }
        }
    }
}
